{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2: Syft Keras的安全模型服务"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，您已经拥有使用正常Keras训练的模型，您就可以准备进行一些隐私预测了。我们可以使用Syft Keras做到这一点。\n",
    "\n",
    "为了保护和服务于此模型，我们将需要三个TFEWorker（服务器）。这是因为TF Encrypted在引擎盖下使用了一种称为[多方计算（MPC）](https://en.wikipedia.org/wiki/Secure_multi-party_computation)的加密技术。想法是将模型权重和输入数据分成多个份额，然后将每个值的份额发送给不同的服务器。关键特性是，如果您查看一台服务器上的共享，则不会显示任何有关原始值（输入数据或模型权重）的信息。\n",
    "\n",
    "我们将像以前的笔记本一样定义Syft Keras模型。但是，有一个技巧：在实例化此模型之前，我们将运行`hook = sy.KerasHook（tf.keras）`。这将为Keras Sequential类添加三个重要的新方法：\n",
    " -`share`：将通过秘密共享保护您的模型；默认情况下，它将使用来自TF Encrypted的SecureNN协议在三个TFEWorker中的每个之间秘密共享您的模型。最重要的是，这将增加提供对加密数据进行预测的功能。\n",
    " -`serve`：此功能将启动服务队列，以便TFEWorkers可以接受来自外部客户端的安全模型上的预测请求。\n",
    " -`shutdown_workers`：完成提供私有预测后，您可以通过运行此函数关闭模型。如果您选择手动管理每个工作程序，它将指导您手动关闭服务器进程。\n",
    "\n",
    "如果您想了解有关MPC的更多信息，可以阅读此出色的[blog](https://mortendahl.github.io/2017/04/17/private-deep-learning-with-mpc/)。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "from tensorflow.keras import Sequential\n",
    "from tensorflow.keras.layers import AveragePooling2D, Conv2D, Dense, Activation, Flatten, ReLU, Activation\n",
    "\n",
    "import syft as sy\n",
    "hook = sy.KerasHook(tf.keras)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如您所见，我们定义了几乎与以前完全相同的模型，除了我们提供了一个“batch_input_shape”。 这允许TF Encrypted通过预定义的张量形状更好地优化安全计算。 对于此MNIST演示，我们将以（1、28、28、1）的形式发送输入数据。\n",
    "我们还返回logit而不是softmax，因为使用MPC执行此操作很复杂，并且我们不需要它来满足预测请求。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_classes = 10\n",
    "input_shape = (1, 28, 28, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "\n",
    "model.add(Conv2D(10, (3, 3), batch_input_shape=input_shape))\n",
    "model.add(AveragePooling2D((2, 2)))\n",
    "model.add(Activation('relu'))\n",
    "model.add(Conv2D(32, (3, 3)))\n",
    "model.add(AveragePooling2D((2, 2)))\n",
    "model.add(Activation('relu'))\n",
    "model.add(Conv2D(64, (3, 3)))\n",
    "model.add(AveragePooling2D((2, 2)))\n",
    "model.add(Activation('relu'))\n",
    "model.add(Flatten())\n",
    "model.add(Dense(num_classes, name=\"logit\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 加载预训练模型权重"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "使用`load_weights`，您可以在训练模型后轻松加载以前保存的权重。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pre_trained_weights = 'short-conv-mnist.h5'\n",
    "model.load_weights(pre_trained_weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 启动工作机"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，让我们创建TF Encrypted所需的TFEWorkers（alice，bob和carol）来执行隐私预测。对于每个TFEWorker，您只需指定一个主机。然后，我们将这些工作机组合在一起。\n",
    "\n",
    "这些工作机运行[TensorFlow服务器](https://www.tensorflow.org/api_docs/python/tf/distribute/Server)，您可以手动进行管理（“AUTO = False”）或要求工作机进行管理您（`AUTO = True`）。 如果选择手动管理它们，则将指示您在调用下面的`cluster.start（）`之后在每个工作人员的主机设备上执行终端命令。如果所有工作程序都托管在单个设备（例如localhost）上，则可以选择让Syft自动管理工作程序的TensorFlow服务器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "AUTO = False\n",
    "\n",
    "alice = sy.TFEWorker(host='localhost:4000', auto_managed=AUTO)\n",
    "bob = sy.TFEWorker(host='localhost:4001', auto_managed=AUTO)\n",
    "carol = sy.TFEWorker(host='localhost:4002', auto_managed=AUTO)\n",
    "\n",
    "cluster = sy.TFECluster(alice, bob, carol)\n",
    "cluster.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 通过共享权重来保护模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "感谢`sy.KerasHook(tf.keras)`，您可以调用share方法将模型转换为TF加密Keras模型。\n",
    "\n",
    "如果您在上面要求手动管理服务器，则在启动所有服务器之前，此步骤将不会完成。 请注意，您的防火墙可能会要求Python接受传入的连接。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.share(cluster)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 服务模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "完美！现在，通过调用`model.serve`，您的模型就可以提供一些隐私的预测了。您可以设置`num_requests`来设置模型所服务的预测请求的数量限制；如果未指定，则将继续提供模型直到被中断。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.serve(num_requests=3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "您已准备好移至**Part 13c**笔记本以请求一些私人预测。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 清理!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "一旦超过您的请求限制，该模型将不再可用于服务请求，但仍由上述三个工作机秘密共享。 您可以通过执行以下单元格杀死工作机。\n",
    "\n",
    "**恭喜您完成第13b部分：使用Syft Keras和TFE进行安全分类！"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.stop()\n",
    "cluster.stop()\n",
    "\n",
    "if not AUTO:\n",
    "    process_ids = !ps aux | grep '[p]ython -m tf_encrypted.player --config' | awk '{print $2}'\n",
    "    for process_id in process_ids:\n",
    "        !kill {process_id}\n",
    "        print(\"Process ID {id} has been killed.\".format(id=process_id))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
